using System;
using System.Net;
using System.Threading;
using Microsoft.Win32.SafeHandles;

namespace InfiniTec.DirectoryServices
{
    class DirectoryServiceConnectionSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        AuthenticationSafeHandle _AuthenticationHandle;

        public DirectoryServiceConnectionSafeHandle()
            : base(true)
        {
        }

        protected override bool ReleaseHandle()
        {
        	SafeNativeMethods.DsUnBind(handle);
            handle = IntPtr.Zero;

            AuthenticationSafeHandle authHandle = Interlocked.Exchange(ref _AuthenticationHandle, null);
            if (authHandle != null) authHandle.Dispose();

            return true;
        }

        public static DirectoryServiceConnectionSafeHandle Create(
            string domainControllerName, string dnsDomainName,
            NetworkCredential credential)
        {
            DirectoryServiceConnectionSafeHandle handle;

        	AuthenticationSafeHandle authenticationHandle = AuthenticationSafeHandle.Create(credential);

			uint result;

			if (credential == CredentialCache.DefaultNetworkCredentials)
			{

				result = SafeNativeMethods.DsBind(domainControllerName, dnsDomainName,
												  out handle);
			}
			else
			{
				authenticationHandle = AuthenticationSafeHandle.Create(credential);

				result = SafeNativeMethods.DsBindWithCred(domainControllerName, dnsDomainName,
															   authenticationHandle, out handle);
				if (result == SafeNativeMethods.Success)
				{
					handle._AuthenticationHandle = authenticationHandle;
				}
				else
				{
					authenticationHandle.Dispose();
				}
			}

            

            if (result == SafeNativeMethods.Success)
            {
                handle._AuthenticationHandle = authenticationHandle;
                return handle;
            }

            authenticationHandle.Dispose();

            switch (result)
            {
                case SafeNativeMethods.InvalidDomainName: throw new ArgumentException("The specified domainname (" + dnsDomainName + ") is invalid.");
                case SafeNativeMethods.NoSuchDomain: throw new ArgumentException("No domain controller is available for the specified domain (" + dnsDomainName + ") or the domain does not exist.");
                default: throw new InvalidOperationException("An unknown error occured while connection to the domain (" + dnsDomainName + "). Error #" + result);
            }
        }
    }



}
